Skip to content

Update plugin ZTools 提供商 v1.0.1#308

Closed
kaineooo wants to merge 1 commit into
ZToolsCenter:mainfrom
kaineooo:plugin/f-provider
Closed

Update plugin ZTools 提供商 v1.0.1#308
kaineooo wants to merge 1 commit into
ZToolsCenter:mainfrom
kaineooo:plugin/f-provider

Conversation

@kaineooo

Copy link
Copy Markdown
Contributor

插件信息

  • 名称: ZTools 提供商
  • 插件ID: f-provider
  • 版本: 1.0.1
  • 描述: OCR + 翻译提供商集合(百度/谷歌/有道/微软翻译、微信 OCR)
  • 作者: kaineooo
  • 类型: 更新

本次变更

  • feat: ZTools OCR + 翻译提供商插件(截图识别 / 代码翻译 / manage)
  • chore: 调整插件命名空间
  • chore: 调整资源url
  • feat: 微信 OCR 原生模块支持 macOS(libwxocr.dylib)
  • feat: 截图识别结果改为独立窗口展示(左图右文 + 拖动缩放)

截图 / 演示

自检清单

  • plugin.json 的 name / title / version / description / author 字段均已检查
  • 已移除调试日志、未使用文件、敏感信息(.env、token、密钥等)
  • 本次 PR 的 diff 仅涉及 plugins/f-provider/ 目录
  • 已在本地 ZTools 客户端实际加载并测试过此插件,主要功能正常
  • 同意以仓库声明的开源协议发布此插件

此 PR 由 ztools-plugin-cli 自动管理:每次 ztools publish 在分支上追加一个 commit,PR 链接保持不变。

- feat: ZTools OCR + 翻译提供商插件(截图识别 / 代码翻译 / manage)
- chore: 调整插件命名空间
- chore: 调整资源url
- feat: 微信 OCR 原生模块支持 macOS(libwxocr.dylib)
- feat: 截图识别结果改为独立窗口展示(左图右文 + 拖动缩放)
@kaineooo kaineooo closed this Jul 10, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the screenshot OCR feature by separating the orchestrator and the result viewer into a multi-page architecture. The main window now coordinates screenshotting and OCR execution, while a new borderless sub-window (screen-ocr-result.html) displays the results with interactive zooming, dragging, and text selection. The review feedback highlights several key improvement opportunities: optimizing performance by caching the plugin logo's file reads and avoiding massive base64 string injection over executeJavaScript (suggesting IndexedDB or localStorage instead), handling asynchronous clipboard errors properly, and capturing pointer events immediately on pointerdown to ensure a smoother dragging experience.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +221 to 234
/** 把数据注入子窗口:调用其 window.__loadScreenOcrResult。 */
function injectData(
win: BrowserWindow.WindowInstance,
data: { image: string; lines: OcrLine[]; isDark: boolean; logo?: string }
): void {
try {
// 序列化为安全的 JSON,避免引号/换行破坏 JS 字符串
const payload = JSON.stringify(data)
const code = `window.__loadScreenOcrResult && window.__loadScreenOcrResult(${payload});`
win.webContents.executeJavaScript(code)
} catch (_) {
/* ignore:兜底注入会再试 */
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

使用 executeJavaScript 注入包含完整截图 Base64 数据(可能达数兆字节)的巨大 JSON 字符串,会导致 Electron 的 IPC 通道和渲染进程主线程在解析、编译和执行该 JS 代码时出现明显的卡顿(Jank)。

建议改进方向:

  1. 利用 localStorageIndexedDB 共享数据:由于主窗口和子窗口处于同源(Same-Origin),可以在主窗口中将大体积的 imagelines 写入 IndexedDBlocalStorage,子窗口启动时自行读取,从而避免通过 executeJavaScript 传递巨型字符串。
  2. 检查窗口是否已被销毁:在调用 win.webContents.executeJavaScript 之前,建议先检查 win && !win.isDestroyed(),避免在窗口意外关闭时引发静默异常。

Comment on lines +80 to +102
// 插件 logo 的 data URI(用于子窗口 <img> 展示图标,注入到渲染层)。
pluginLogoDataUrl() {
try {
const p = path.join(__dirname, '..', 'logo.png')
const buf = fs.readFileSync(p)
return 'data:image/png;base64,' + buf.toString('base64')
} catch (_) {
return ''
}
},

// 插件 logo 的 NativeImage 对象(用于 createBrowserWindow 的 icon)。
// Windows 下传字符串路径时任务栏按钮仍按 AppID 取宿主 exe 图标,
// 传 NativeImage 才能让任务栏真正显示插件图标。
pluginLogoNativeImage() {
try {
// ZTools 在 preload 提供 require('electron').nativeImage
const { nativeImage } = require('electron')
return nativeImage.createFromPath(path.join(__dirname, '..', 'logo.png'))
} catch (_) {
return null
}
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

每次调用 pluginLogoDataUrl 都会进行同步文件读取 (fs.readFileSync),而每次调用 pluginLogoNativeImage 都会重新创建 NativeImage 对象。由于插件图标在运行期间不会改变,建议对这两个方法的结果进行缓存,以避免不必要的磁盘 I/O 和内存开销。

Comment on lines +74 to +84
function copyText(text: string) {
if (!text) return
try {
navigator.clipboard?.writeText(text)
} catch (_) {
/* 子窗口可能无 clipboard 权限,静默失败 */
}
copied.value = text
if (copiedTimer) window.clearTimeout(copiedTimer)
copiedTimer = window.setTimeout(() => (copied.value = ''), 1200)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

navigator.clipboard.writeText 返回的是一个 Promise。在当前的实现中,同步的 try...catch 块无法捕获异步的 Promise Rejection。如果剪贴板写入失败(例如子窗口失去焦点或权限不足),将会导致未捕获的 Promise 拒绝(Unhandled Promise Rejection)。

建议使用 .catch() 显式捕获并处理该异步错误。

Comment on lines +310 to +336
function onPointerDown(e: PointerEvent) {
if (e.button !== 0) return
pointerActive = true
didDrag = false
dragStart = { x: e.clientX, y: e.clientY }
dragOrigin = { x: offsetX.value, y: offsetY.value }
}
function onPointerMove(e: PointerEvent) {
if (!pointerActive) return
const dx = e.clientX - dragStart.x
const dy = e.clientY - dragStart.y
if (!dragging.value && Math.hypot(dx, dy) < DRAG_THRESHOLD) return
if (!dragging.value) {
dragging.value = true
didDrag = true
;(e.currentTarget as HTMLElement).setPointerCapture?.(e.pointerId)
}
offsetX.value = dragOrigin.x + dx
offsetY.value = dragOrigin.y + dy
}
function onPointerUp(e: PointerEvent) {
pointerActive = false
if (dragging.value) {
dragging.value = false
;(e.currentTarget as HTMLElement).releasePointerCapture?.(e.pointerId)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

当前在 onPointerMove 达到拖拽阈值后才调用 setPointerCapture。如果用户在按下鼠标后极快地将指针移出 stage 边界(在移动距离达到 DRAG_THRESHOLD 之前),pointermove 事件将不会再分发给 stage,导致拖拽无法启动。

建议改进:
onPointerDown 时立即捕获指针,并在 onPointerUp 时统一释放。这样可以确保拖拽手势在任何移动速度下都能 100% 稳定触发,同时简化了 onPointerMove 中的逻辑。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants